package org.wk.core.db.dao;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

public class SimpleGenericJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
		implements GenericJpaRepository<T, ID>, JpaSpecificationExecutor<T> {
	private final EntityManager em;
	private final JpaEntityInformation<T, ?> entityInformation;

	public SimpleGenericJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
		super(entityInformation, entityManager);
		this.em = entityManager;
		this.entityInformation = entityInformation;
	}

	public SimpleGenericJpaRepository(Class<T> domainClass, EntityManager em) {
		this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
	}

	@Transactional
	@Override
	public void saveBatch(List<T> data) {
		// TODO Auto-generated method stub
//		entityInformation.getJavaType();
		if(data!=null){
			for (int i = 0; i < data.size(); i++) {
				T t = data.get(i);
				em.persist(t);
				if(i%20==0){
					em.flush();
					em.clear();
				}
			}
		}
	}

	@Transactional
	@Override
	public void updateBatch(List<T> data) {
		// TODO Auto-generated method stub
		if(data!=null){
			for (int i = 0; i < data.size(); i++) {
				T t = data.get(i);
				BeanWrapper beanWrapper = new BeanWrapperImpl(t);
				Object id = beanWrapper.getPropertyValue("id");
				if(id==null){
					continue;
				}
				em.merge(t);
				if(i%20==0){
					em.flush();
					em.clear();
				}
			}
		}
	}
	
	@Transactional
	@Override
	public void deleteBatch(List<T> data){
		if(data!=null){
			for (int i = 0; i < data.size(); i++) {
				T t = data.get(i);
				em.remove(t);
				if(i%20==0){
					em.flush();
					em.clear();
				}
			}
		}
	}

	@Transactional
	@Override
	public void saveOrUpdate(T entity) {
		// TODO Auto-generated method stub
		BeanWrapper beanWrapper = new BeanWrapperImpl(entity);
		Object id = beanWrapper.getPropertyValue("id");
		if(id instanceof String){
			if(StringUtils.isEmpty(id)){
				beanWrapper.setPropertyValue("id", null);
				id = null;
			}
		}
		if(id!=null){
			em.merge(entity);
		}else{
			em.persist(entity);
		}
		em.flush();
	}
	
	@Transactional
	@Override
	public void update(T entity) {
		// TODO Auto-generated method stub
		em.merge(entity);
		em.flush();
	}
	
	@Override
	public List<T> findAll(Specification<T> specification){
		return super.findAll(specification);
	}
	@Override
	public Page<T> findAll(Specification<T> specification,Pageable pageable){
		return super.findAll(specification, pageable);
	}
}
